#include "TcpConnection.h"
#include "Channel.h"
#include "EventLoop.h"
#include "Logger.h"
#include "Socket.h"

#include <errno.h>
#include <stdio.h>
#include <string.h>

void TcpConnection::SetState(int state) {
    state_ = state;
}

void TcpConnection::HandleRead() {
    ssize_t n = in_buffer_.ReadFd(socket_->Fd());
    // LOG_INFO("Read %zd bytes from fd = %d", n, socket_->Fd());
    LOG_INFO("buffer: %u - %u - %u", in_buffer_.PrependableBytes(), in_buffer_.ReadableBytes(),
             in_buffer_.WriteableBytes());
    if (n > 0) {
        LOG_INFO("Readable bytes in buffer: %zu", in_buffer_.ReadableBytes());
        if (message_callback_) {
            message_callback_(shared_from_this(), &in_buffer_);
        } else {
            LOG_ERROR("No message_callback_ set for connection: %s", name_.c_str());
        }
    } else if (n == 0) {
        LOG_INFO("Client closed connection: %s", name_.c_str());
        HandleClose();
    } else {
        LOG_INFO("Read error on fd %d: %s", socket_->Fd(), strerror(errno));
        HandleError();
    }
}

void TcpConnection::HandleWrite() {
    LOG_INFO("HandleWrite: fd=%d", socket_->Fd());

    // 检查输出缓冲区是否有数据可写
    if (out_buffer_.ReadableBytes() > 0) {
        ssize_t n = out_buffer_.WriteFd(socket_->Fd());
        LOG_INFO("WriteFd returned: %zd bytes", n);

        if (n > 0) {
            out_buffer_.Retrieve(n);
            LOG_INFO("Remaining bytes in output buffer: %zu", out_buffer_.ReadableBytes());

            if (out_buffer_.ReadableBytes() == 0) {
                LOG_INFO("All data sent, disabling write events");
                channel_->DisableWrite();

                // 检查回调函数是否存在
                if (write_complete_callback_) {
                    write_complete_callback_(shared_from_this());
                }

                // 如果正在断开连接，现在可以关闭写端了
                if (state_ == DisConnecting) {
                    LOG_INFO("Shutting down after all data sent");
                    ShutdownInLoop();
                }
            }
        } else if (n < 0) {
            LOG_ERROR("Write error on fd %d: %s", socket_->Fd(), strerror(errno));
            HandleError();
        }
    } else {
        LOG_INFO("No data to write, disabling write events");
        channel_->DisableWrite();
    }
}

void TcpConnection::HandleClose() {
    LOG_INFO("HandleClose: %s", name_.c_str());
    SetState(DisConnected);
    channel_->DisableAll();
    channel_->Remove();

    if (close_callback_) {
        close_callback_(shared_from_this());
    }
}

void TcpConnection::HandleError() {
    int optval;
    socklen_t optlen = sizeof(optval);
    int err = 0;
    if (::getsockopt(channel_->Fd(), SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) {
        err = errno;
    } else {
        err = optval;
    }
    LOG_ERROR("HandleError name:%s - SO_ERROR:%d", name_.c_str(), err);
}

void TcpConnection::Send(const std::string& buf) {
    LOG_INFO("Send: %s, %zu bytes", name_.c_str(), buf.size());

    if (state_ == Connected) {
        if (loop_->IsInLoop()) {
            SendInLoop(buf.c_str(), buf.size());
        } else {
            loop_->RunInLoop(std::bind(&TcpConnection::SendInLoop, this, buf.c_str(), buf.size()));
        }
    } else {
        LOG_ERROR("Attempt to send data on disconnected connection: %s", name_.c_str());
    }
}

void TcpConnection::SendInLoop(const char* data, size_t len) {
    LOG_INFO("SendInLoop %s, %zu bytes", name_.c_str(), len);

    if (state_ != Connected) {
        // LOG_ERROR("Connection not connected, state: %d", state_);
        return;
    }

    ssize_t nwrote = 0;
    size_t remaining = len;

    if (!channel_->WriteAble() && out_buffer_.ReadableBytes() == 0) {
        nwrote = write(socket_->Fd(), data, len);
        LOG_INFO("Direct write: %zd bytes", nwrote);

        if (nwrote >= 0) {
            remaining = len - nwrote;
            if (remaining == 0 && write_complete_callback_) {
                LOG_INFO("All data sent directly");
                loop_->QueueInLoop(std::bind(write_complete_callback_, shared_from_this()));
            }
        } else {
            if (errno != EWOULDBLOCK) {
                LOG_ERROR("Write error: %s", strerror(errno));
                HandleError();
                return;
            }
            nwrote = 0;  // EWOULDBLOCK 表示写了0字节
        }
    }

    if (remaining > 0) {
        LOG_INFO("Buffering remaining %zu bytes", remaining);

        size_t oldLen = out_buffer_.ReadableBytes();
        if (oldLen + remaining >= high_water_mark_ && oldLen < high_water_mark_ && high_water_mark_callback_) {
            LOG_INFO("High water mark reached: %zu", oldLen + remaining);
            loop_->QueueInLoop(std::bind(high_water_mark_callback_, shared_from_this(), oldLen + remaining));
        }

        out_buffer_.Append(data + nwrote, remaining);

        if (!channel_->WriteAble()) {
            LOG_INFO("Enabling write events");
            channel_->EnableWrite();
        }
    }
}

void TcpConnection::ConnectEstablished() {
    // 1. 修改连接状态 2. 启动读事件监控 3. 调用回调函数
    // 一旦启动读事件监控就有可能立即触发读事件，如果启动了非活跃连接销毁，那么此时就会去刷新定时任务延迟定时任务的执行
    // 如果把启动读事件监控放在构造函数中，此时定时任务还没有添加，此时在事件轮中是找不到该定时任务的，逻辑上存在问题
    // 所以要保证启动读事件监控要在设置了定时任务之后执行
    SetState(Connected);
    channel_->EnableRead();
    connection_callback_(shared_from_this());
}

void TcpConnection::ConnectDestroyed() {
    SetState(DisConnected);
    channel_->DisableAll();
    channel_->Remove();
}

TcpConnection::TcpConnection(EventLoop* loop,
                             std::string name,
                             int connfd,
                             InetAddress local_addr,
                             InetAddress peer_addr)
    : loop_(loop),
      name_(name),
      socket_(new Socket(connfd)),
      channel_(new Channel(connfd, loop_)),
      state_(Connecting),
      local_addr_(local_addr),
      peer_addr_(peer_addr),
      high_water_mark_(64 * 1024 * 1024)  // 64M
{
    // channel of connfd
    channel_->SetReadCallback(std::bind(&TcpConnection::HandleRead, this));
    channel_->SetWriteCallback(std::bind(&TcpConnection::HandleWrite, this));
    channel_->SetCloseCallback(std::bind(&TcpConnection::HandleClose, this));
    channel_->SetErrorCallback(std::bind(&TcpConnection::HandleError, this));
}

void TcpConnection::SetConnectionCallback(const ConnectionCallback& cb) {
    connection_callback_ = cb;
}
void TcpConnection::SetMessageCallback(const MessageCallback& cb) {
    message_callback_ = cb;
}
void TcpConnection::SetWriteCompleteCallback(const WriteCompleteCallback& cb) {
    write_complete_callback_ = cb;
}

void TcpConnection::Shutdown() {
    if (state_ == Connected) {
        SetState(DisConnecting);
        loop_->RunInLoop(std::bind(&TcpConnection::ShutdownInLoop, this));
    }
}

void TcpConnection::ShutdownInLoop() {
    if (!channel_->WriteAble())  // 说明当前outputBuffer_的数据全部向外发送完成
    {
        socket_->Shutdown();
    }
}

TcpConnection::~TcpConnection() {
    LOG_INFO("TcpConnection::[%s] at fd=%d", name_.c_str(), channel_->Fd());
}

std::string TcpConnection::Name() {
    return name_;
}

EventLoop* TcpConnection::Loop() {
    return loop_;
}

void TcpConnection::SetHttpContext(const HttpContext& context) {
    http_context_ = context;
}

HttpContext* TcpConnection::GetHttpContext() {
    return &http_context_;
}